//
// Created by denglibin on 19-4-13.
//

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
#include<sys/types.h>

/*
    进程一旦调用了 wait，就立即阻塞自己，由wait自动分析是否当前进程的某个子进程已经退出，如果让它找到了这样一个已经变成僵尸的子进程，
wait 就会收集这个子进程的信息， 并把它彻底销毁后返回；如果没有找到这样一个子进程，wait就会一直阻塞在这里，直到有一个出现为止。
一次wait调用只回收一个子进程

函数说明
    wait()会暂时停止目前进程的执行，直到有信号来到或子进程结束。如果在调用wait（）时子进程已经结束，则wait（）会立即返回子进程结束状态值。
子进程的结束状态值会由参数status 返回，而子进程的进程识别码也会一快返回。如果不在意结束状态值，则参数status 可以设成NULL。子进程的结束状态值请参考waitpid（）。

返回值
    如果执行成功则返回子进程识别码（PID），如果有错误发生则返回-1。失败原因存于errno 中。

子进程的结束状态返回后存于status，下面有几个宏可判别结束情况：
WIFEXITED（status）如果子进程正常结束则为非0 值。
WEXITSTATUS（status）取得子进程exit（）返回的结束代码，一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
WIFSIGNALED（status）如果子进程是因为信号而结束则此宏值为真
WTERMSIG（status） 取得子进程因信号而中止的信号代码，一般会先用WIFSIGNALED 来判断后才使用此宏。
WIFSTOPPED（status） 如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。
WSTOPSIG（status） 取得引发子进程暂停的信号代码，一般会先用WIFSTOPPED 来判断后才使用此宏。
*/
static int main_(int argc, char** argv)
{
    pid_t pid;
    int status, a,b,d,i;
    if(fork() == 0)
    {
        printf("This is child process. pid=%d\n",getpid());
        sleep(20);
        exit(76);//退出值 不超过128
    }
    else
    {
        sleep(0);
        printf("This is parent process. wait for child...\n");
        //pid = wait(NULL);
        pid = wait(&status);//如果成功，wait会返回被收集的子进程的进程ID 回收多个用循环
        a= WIFEXITED(status); //为非0 进程正常结束,如果调用进程没有子进程，调用就会失败，此时wait返回-1
        printf("a=%d", a);
        if(a)
        {
            i = WEXITSTATUS(status); //返回子进程的退出值
            printf("child is pid=%d. exit status=%d\n",pid,i);
        }
        b = WIFSIGNALED(status);//为非0 程序异常终止
        printf("b=%d", b);
        if(b)
        {
            d = WTERMSIG(status); //取得使进程终止的那个信号的编号
            printf("d=%d", d);
        }


        //输出进程信息
        system("ps -o pid,ppid,state,tty,command");
    }
    return 0;
}
